from __future__ import annotations

from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from sqlmodel import select
from sqlalchemy.ext.asyncio import AsyncSession

from ..db import get_session
from ..deps import require_admin
from ..models import AgentStrategy, RunMode, utcnow
from ..services.agent_manager import agent_manager


router = APIRouter(
    prefix="/agent/strategies",
    tags=["agent-strategies"],
    dependencies=[Depends(require_admin)],
)


class AgentStrategyCreate(BaseModel):
    name: str
    desc: Optional[str] = None
    account_name: str
    connector_name: str
    trading_pair: str
    mode: RunMode = RunMode.shadow
    interval_seconds: int = Field(120, ge=1, le=3600)
    max_notional_usd: float = Field(..., gt=0)
    max_slippage_bps: int = Field(..., ge=0)
    max_daily_loss_usd: float = Field(..., ge=0)
    enabled: bool = True


class AgentStrategyUpdate(BaseModel):
    desc: Optional[str] = None
    account_name: Optional[str] = None
    connector_name: Optional[str] = None
    trading_pair: Optional[str] = None
    mode: Optional[RunMode] = None
    interval_seconds: Optional[int] = Field(None, ge=1, le=3600)
    max_notional_usd: Optional[float] = Field(None, gt=0)
    max_slippage_bps: Optional[int] = Field(None, ge=0)
    max_daily_loss_usd: Optional[float] = Field(None, ge=0)
    enabled: Optional[bool] = None


@router.post("")
async def create_strategy(payload: AgentStrategyCreate, session: AsyncSession = Depends(get_session)) -> AgentStrategy:
    obj = AgentStrategy(
        name=payload.name,
        desc=payload.desc,
        account_name=payload.account_name,
        connector_name=payload.connector_name,
        trading_pair=payload.trading_pair,
        mode=payload.mode,
        interval_seconds=payload.interval_seconds,
        max_notional_usd=payload.max_notional_usd,
        max_slippage_bps=payload.max_slippage_bps,
        max_daily_loss_usd=payload.max_daily_loss_usd,
        enabled=payload.enabled,
    )
    session.add(obj)
    await session.commit()
    await session.refresh(obj)
    agent_manager.request_refresh()
    return obj


@router.put("/{strategy_id}")
async def update_strategy(
    strategy_id: int,
    payload: AgentStrategyUpdate,
    session: AsyncSession = Depends(get_session),
) -> AgentStrategy:
    result = await session.execute(select(AgentStrategy).where(AgentStrategy.id == strategy_id))
    obj = result.scalar_one_or_none()
    if not obj:
        raise HTTPException(status_code=404, detail="strategy_not_found")

    update_data = payload.dict(exclude_unset=True)
    for key, value in update_data.items():
        setattr(obj, key, value)
    obj.updated_at = utcnow()

    session.add(obj)
    await session.commit()
    await session.refresh(obj)
    agent_manager.request_refresh()
    return obj


@router.get("", response_model=List[AgentStrategy])
async def list_strategies(session: AsyncSession = Depends(get_session)) -> List[AgentStrategy]:
    result = await session.execute(select(AgentStrategy).order_by(AgentStrategy.created_at.desc()))
    rows = result.scalars().all()
    # 运行时状态：running/stopped
    runtime = agent_manager.runtime_status()
    for row in rows:
        if row.id in runtime:
            row.desc = (row.desc or "") + f" [runtime={runtime[row.id]}]"
    return rows
